// Terrain.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "..\inc\terrain.h"

#include <Physics/Dynamics/Entity/hkpRigidBody.h>

using namespace TerrainSystem;
using namespace Common;

Terrain::Terrain()
	:m_vStartPos(Vector3::ZERO),m_uWidth(0),m_uHeight(0),m_fUnitSize(1.0f),m_fPoints(NULL),m_vScale(Vector3::UNIT_SCALE)//,m_pTerrainPhysicsShape(NULL),m_pTerrainRigidBody(NULL)
{
}

Terrain::~Terrain()
{
	if( m_fPoints != NULL )
	{
		delete []m_fPoints;
		m_fPoints = NULL;
	}
}
/*
void Terrain::DestroyPhysicsShape( hkpWorld* pPhyWorld )
{
	if( m_pTerrainRigidBody == NULL )
		return;

	if( !pPhyWorld->removeEntity( m_pTerrainRigidBody ) )
		assert( false );

	m_pTerrainRigidBody = NULL;

	if( m_pTerrainPhysicsShape != NULL )
		delete m_pTerrainPhysicsShape;
 
	m_pTerrainPhysicsShape = NULL;
}

void Terrain::InitPhysicsShape( hkpWorld* pPhyWorld )
{
	pPhyWorld->lock();

	if( m_pTerrainPhysicsShape != NULL )
		delete m_pTerrainPhysicsShape;

	hkpSampledHeightFieldBaseCinfo ci;
	ci.m_xRes = m_uWidth + 1;
	ci.m_zRes = m_uHeight + 1;
	ci.m_scale = hkVector4( m_vScale.x, m_vScale.y, m_vScale.z );

	TerrainPhysicsShape* heightFieldShape = new TerrainPhysicsShape( ci, this );
	
	// Now that we have a shape all we need is the fixed body to represent it in the 
	// the simulation. Standard rigid body setup.
	{
		hkpRigidBodyCinfo rci;
		rci.m_motionType = hkpMotion::MOTION_FIXED;
		rci.m_position.setMul4( -0.5f, heightFieldShape->m_extents ); // center the heightfield
		rci.m_shape = heightFieldShape;
		rci.m_friction = 0.2f;

		m_pTerrainRigidBody = new hkpRigidBody( rci );
		m_pTerrainRigidBody->setPosition( hkVector4( m_vStartPos.x, m_vStartPos.y, m_vStartPos.z ) );

		pPhyWorld->addEntity(m_pTerrainRigidBody);
		m_pTerrainRigidBody->removeReference();
	}

	// Just need to remove the reference we hold to the shape, and that is it.
	heightFieldShape->removeReference();

	pPhyWorld->unlock();
}
*/
void Terrain::SetStartPos( const Common::Vector3& vStartPos )
{
	m_vStartPos = vStartPos;
}

Common::Vector3 Terrain::GetStartPos( void ) const
{
	return m_vStartPos;
}

void Terrain::SetExtent( uint16 uWidth, uint16 uHeight )
{
	if( m_fPoints != NULL )
	{
		delete []m_fPoints;
		m_fPoints = NULL;
	}

	m_fPoints = new float[ ( uWidth + 1 ) * ( uHeight + 1 ) ];
	m_uWidth  = uWidth;
	m_uHeight = uHeight;

	::memset( m_fPoints, 0, sizeof(float) * ( uWidth + 1 ) * ( uHeight + 1 ) );
}

void Terrain::GetExtent( uint16 &uWidth, uint16 &uHeight ) const
{
	uWidth = m_uWidth;
	uHeight = m_uHeight;
}

void Terrain::SetScale( Common::Vector3 vScale )
{
	m_vScale = vScale;
}

Common::Vector3 Terrain::GetScale( void ) const
{
	return m_vScale;
}

bool Terrain::SetHeight( uint16 uIdxX, uint16 uIdxY, float fHeight )
{
	if( uIdxX > m_uWidth + 1 || uIdxY > m_uHeight + 1 )
		return false;

	uint16 uIdx = ( m_uWidth + 1 ) * uIdxY + uIdxX;

	m_fPoints[uIdx] = fHeight;

	return true;
}

bool Terrain::GetHeight( uint16 uIdxX, uint16 uIdxY, float &fHeight ) const
{
	if( uIdxX > m_uWidth || uIdxY > m_uHeight )
		return false;

	uint16 uIdx = ( m_uWidth + 1 ) * uIdxY + uIdxX;

	fHeight = m_fPoints[uIdx];

	return true;
}

float Terrain::GetUnitSize( void ) const
{
	return m_fUnitSize;
}

void Terrain::SetUnitSize( float fUnitSize )
{
	assert( fUnitSize > 0.0f );
	m_fUnitSize = fUnitSize;
}
